package com.common.atom.seal.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.*;
import java.io.*;

/**
 * description: SealUtils <br>
 * date: 2023/4/13  <br>
 * author: zss <br>
 * version: 1.0.0 <br>
 */
public class SealUtils {

    private static final Logger logger = LoggerFactory.getLogger(SealUtils.class);

    // 透明切割阈值
    private static final int STARDER_ARGB = 210;
    private static final int STARDER_ARGB_LOW = 130;
    private static final int STARDER_ARGB_SAMPLING_DISTANCE = 8;

    /**
     * 印章图片宽度
     */
    private static final int SEAL_DEFAULT_WIDTH = 400;

    public static BufferedImage createTransparentBufferedImage(int width, int height) {
        BufferedImage bufferedImage = new BufferedImage(width, height, 1);
        Graphics2D graphics2d = (Graphics2D) bufferedImage.getGraphics();
        graphics2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        graphics2d.setBackground(Color.WHITE);
        graphics2d.clearRect(0, 0, width, height);
        graphics2d.dispose();
        Image image = makeColorTransparent(bufferedImage, Color.WHITE);
        bufferedImage = imageToBufferedImage(image);
        return bufferedImage;
    }

    public static Image makeColorTransparent(BufferedImage bufferedImage, final Color color) {
        ImageFilter filter = new RGBImageFilter() {
            int markerRGB = color.getRGB() | 0xFF000000;

            @Override
            public final int filterRGB(int x, int y, int rgb) {
                if ((rgb | 0xFF000000) == this.markerRGB) {
                    return 0xFFFFFF & rgb;
                }
                return rgb;
            }
        };
        ImageProducer ip = new FilteredImageSource(bufferedImage.getSource(), filter);
        return Toolkit.getDefaultToolkit().createImage(ip);
    }

    public static BufferedImage imageToBufferedImage(Image image) {
        BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), 2);

        Graphics2D g2 = bufferedImage.createGraphics();
        g2.drawImage(image, 0, 0, null);
        g2.dispose();
        return bufferedImage;
    }

    /**
     * 设置图片背景透明和颜色
     *
     * @param imageByte
     * @param colorMode 1:red、2:green、3blue
     * @return
     */
    public static byte[] changeColorAndTransferAlpha(byte[] imageByte, String colorMode, int cutout) throws IOException {
        return LimpidUtils.transferAlpha(new ByteArrayInputStream(imageByte), colorMode, cutout);
    }

    /**
     * 切除图片边缘透明化像素
     *
     * @param image
     * @return
     * @throws IOException
     */
    public static byte[] marginAdjust(BufferedImage image) throws IOException {

        if (image == null) {
            throw new IOException("Image object can not be null!");
        }
        byte[] imgBytes = transferAlpha(image);
        ByteArrayInputStream in = new ByteArrayInputStream(imgBytes);
        image = ImageIO.read(in);
        class Coord {
            private int x;
            private int y;

            public int getX() {
                return x;
            }

            public void setX(int x) {
                this.x = x;
            }

            public int getY() {
                return y;
            }

            public void setY(int y) {
                this.y = y;
            }

            @Override
            public String toString() {
                return "Coord [x=" + x + ", y=" + y + "]";
            }
        }

        Coord top = new Coord();
        Coord down = new Coord();
        Coord left = new Coord();
        Coord right = new Coord();

        // 从左至右
        Boolean checkLeft = false;
        for (int x = image.getMinX(); x < image.getWidth(); x++) {
            for (int y = image.getMinY(); y < image.getHeight(); y++) {
                // System.out.println(x+":"+y+":"+getGray(image.getRGB(x, y)));
                if (getGray(image.getRGB(x, y)) < STARDER_ARGB) {
                    left.setX(x);
                    left.setY(y);
                    checkLeft = true;
                    break;
                }
            }
            if (checkLeft) {
                break;
            }
        }
        // 从右至左
        Boolean checkRight = false;
        for (int x = image.getWidth() - 1; x >= image.getMinX(); x--) {
            for (int y = image.getMinY(); y < image.getHeight(); y++) {
                if (getGray(image.getRGB(x, y)) < STARDER_ARGB) {
                    right.setX(x);
                    right.setY(y);
                    checkRight = true;
                    break;
                }
            }
            if (checkRight) {
                break;
            }
        }
        // 从下至上
        Boolean checkDown = false;
        for (int y = image.getMinY(); y < image.getHeight(); y++) {
            for (int x = image.getMinX(); x < image.getWidth(); x++) {
                if (getGray(image.getRGB(x, y)) < STARDER_ARGB) {
                    down.setX(x);
                    down.setY(y);
                    checkDown = true;
                    break;
                }
            }
            if (checkDown) {
                break;
            }
        }
        // 从上至下
        Boolean checkTop = false;
        for (int y = image.getHeight() - 1; y > image.getMinY(); y--) {
            for (int x = image.getMinX(); x < image.getWidth(); x++) {
                if (getGray(image.getRGB(x, y)) < STARDER_ARGB) {
                    top.setX(x);
                    top.setY(y);
                    checkTop = true;
                    break;
                }
            }
            if (checkTop) {
                break;
            }
        }
        int newWidth = Math.abs(right.getX() - left.getX() + 1);
        int newHeight = Math.abs(top.getY() - down.getY() + 1);
        BufferedImage newImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
        for (int x = newImage.getMinX(); x < newImage.getWidth(); x++) {
            for (int y = newImage.getMinY(); y < newImage.getHeight(); y++) {
                int rgb = image.getRGB(x + left.getX(), y + down.getY());
                newImage.setRGB(x, y, rgb);
            }
        }
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(newImage, "png", baos);
        byte[] outBytes = baos.toByteArray();

        return outBytes;
    }

    /**
     * 获取color平均像素值
     *
     * @param color
     * @return
     */
    private static int getGray(int color) {
        int[] rgb = new int[3];
        rgb[0] = (color & 0xFF0000) >> 16;
        rgb[1] = (color & 0xFF00) >> 8;
        rgb[2] = color & 0xFF;
        return (rgb[0] + rgb[1] + rgb[2]) / 3;
    }

    private static int samplingDistance(BufferedImage bufferedImage) {
        int distance = 0;

        int rgb = bufferedImage.getRGB(0, bufferedImage.getMinY());
        int R = (rgb & 0xff0000) >> 16;
        int G = (rgb & 0xff00) >> 8;
        int B = rgb & 0xff;
        int leftTop = getMaxColor((R - (G + B) / 2), (G - (R + B) / 2), (B - (G + R) / 2));

        if (leftTop > 50) {
            leftTop = 0;
        }
        rgb = bufferedImage.getRGB(bufferedImage.getWidth() - 1, bufferedImage.getMinY());
        R = (rgb & 0xff0000) >> 16;
        G = (rgb & 0xff00) >> 8;
        B = rgb & 0xff;
        int rightTop = getMaxColor((R - (G + B) / 2), (G - (R + B) / 2), (B - (G + R) / 2));

        if (rightTop > 50) {
            rightTop = 0;
        }

        rgb = bufferedImage.getRGB(0, bufferedImage.getHeight() - 1);
        R = (rgb & 0xff0000) >> 16;
        G = (rgb & 0xff00) >> 8;
        B = rgb & 0xff;
        int leftBottom = getMaxColor((R - (G + B) / 2), (G - (R + B) / 2), (B - (G + R) / 2));

        if (leftBottom > 50) {
            leftBottom = 0;
        }

        rgb = bufferedImage.getRGB(bufferedImage.getWidth() - 1, bufferedImage.getHeight() - 1);
        R = (rgb & 0xff0000) >> 16;
        G = (rgb & 0xff00) >> 8;
        B = rgb & 0xff;
        int rightBottom = getMaxColor((R - (G + B) / 2), (G - (R + B) / 2), (B - (G + R) / 2));

        if (rightBottom > 50) {
            rightBottom = 0;
        }

        if (leftTop > distance) {
            distance = leftTop;
        }
        if (rightTop > distance) {
            distance = rightTop;
        }
        if (leftBottom > distance) {
            distance = leftBottom;
        }
        if (rightBottom > distance) {
            distance = rightBottom;
        }

        return distance;

    }

    private static int samplingStarder(BufferedImage bufferedImage) {

        int minStarder = 255;
        int rgb = bufferedImage.getRGB(0, bufferedImage.getMinY());
        int R = (rgb & 0xff0000) >> 16;
        int G = (rgb & 0xff00) >> 8;
        int B = rgb & 0xff;

        if ((R < STARDER_ARGB && G < STARDER_ARGB && B < STARDER_ARGB)
                && (R > STARDER_ARGB_LOW && G > STARDER_ARGB_LOW && B > STARDER_ARGB_LOW)) {
            minStarder = getMinColor(R, G, B) < minStarder ? getMinColor(R, G, B) : minStarder;
        }

        // System.out.println(" R:"+R+" G:"+G+" B:"+B);
        // System.out.println(minStarder+"&"+getMinColor(R,G,B));

        rgb = bufferedImage.getRGB(bufferedImage.getWidth() - 1, bufferedImage.getMinY());
        R = (rgb & 0xff0000) >> 16;
        G = (rgb & 0xff00) >> 8;
        B = rgb & 0xff;

        if ((R < STARDER_ARGB && G < STARDER_ARGB && B < STARDER_ARGB)
                && (R > STARDER_ARGB_LOW && G > STARDER_ARGB_LOW && B > STARDER_ARGB_LOW)) {
            minStarder = getMinColor(R, G, B) < minStarder ? getMinColor(R, G, B) : minStarder;
        }

        // System.out.println(" R:"+R+" G:"+G+" B:"+B);
        // System.out.println(minStarder);

        rgb = bufferedImage.getRGB(0, bufferedImage.getHeight() - 1);
        R = (rgb & 0xff0000) >> 16;
        G = (rgb & 0xff00) >> 8;
        B = rgb & 0xff;

        if ((R < STARDER_ARGB && G < STARDER_ARGB && B < STARDER_ARGB)
                && (R > STARDER_ARGB_LOW && G > STARDER_ARGB_LOW && B > STARDER_ARGB_LOW)) {
            minStarder = getMinColor(R, G, B) < minStarder ? getMinColor(R, G, B) : minStarder;
        }

        // System.out.println(" R:"+R+" G:"+G+" B:"+B);
        // System.out.println(minStarder);
        rgb = bufferedImage.getRGB(bufferedImage.getWidth() - 1, bufferedImage.getHeight() - 1);
        R = (rgb & 0xff0000) >> 16;
        G = (rgb & 0xff00) >> 8;
        B = rgb & 0xff;

        if ((R < STARDER_ARGB && G < STARDER_ARGB && B < STARDER_ARGB)
                && (R > STARDER_ARGB_LOW && G > STARDER_ARGB_LOW && B > STARDER_ARGB_LOW)) {
            minStarder = getMinColor(R, G, B) < minStarder ? getMinColor(R, G, B) : minStarder;
        }

        // System.out.println(" R:"+R+" G:"+G+" B:"+B);
        // System.out.println(minStarder);

        return minStarder;

    }

    public static byte[] transferAlpha(Image image) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        try {
            ImageIcon imageIcon = new ImageIcon(image);
            BufferedImage bufferedImage = new BufferedImage(imageIcon.getIconWidth(), imageIcon.getIconHeight(), 6);
            Graphics2D g2D = (Graphics2D) bufferedImage.getGraphics();
            g2D.drawImage(imageIcon.getImage(), 0, 0, imageIcon.getImageObserver());
            int alpha = 0;
            for (int j1 = bufferedImage.getMinY(); j1 < bufferedImage.getHeight(); j1++) {
                for (int j2 = bufferedImage.getMinX(); j2 < bufferedImage.getWidth(); j2++) {
                    int rgb = bufferedImage.getRGB(j2, j1);
                    if (rgb == 0) {
                        rgb = -1;
                    }

                    int R = (rgb & 0xff0000) >> 16;
                    int G = (rgb & 0xff00) >> 8;
                    int B = rgb & 0xff;
                    if (R > STARDER_ARGB && G > STARDER_ARGB && B > STARDER_ARGB) {
                        rgb = alpha + 1 << 24 | rgb & 0xffffff;
                    }
                    bufferedImage.setRGB(j2, j1, rgb);
                }

            }

            g2D.drawImage(bufferedImage, 0, 0, imageIcon.getImageObserver());
            ImageIO.write(bufferedImage, "png", byteArrayOutputStream);
        } catch (Exception e) {
            return null;
        }

        return byteArrayOutputStream.toByteArray();
    }

    // 获得指定文件的byte数组
    public static byte[] getBytes(String filePath) {
        byte[] buffer = null;
        try (FileInputStream fis = new FileInputStream(new File(filePath))) {
            ByteArrayOutputStream bos = new ByteArrayOutputStream(1000);
            byte[] b = new byte[1000];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            fis.close();
            bos.close();
            buffer = bos.toByteArray();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return buffer;
    }

    // 根据byte数组，生成文件
    public static void saveImgFile(byte[] bfile, String fileName) {
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        File file = null;
        try {

            file = new File(fileName);

            if (!file.exists() && file.isDirectory()) {
                file.mkdirs();
            } else if (!file.isDirectory()) {
                File parentDir = file.getParentFile();
                if (!parentDir.exists()) {
                    parentDir.mkdirs();
                }
            }

            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(bfile);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e1) {
                    logger.error(e1.getMessage(), e1);
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e1) {
                    logger.error(e1.getMessage(), e1);
                }
            }
        }
    }

    private static int getMinColor(int r, int g, int b) {
        int min = 255;
        min = r < min ? r : min;
        min = g < min ? g : min;
        min = b < min ? b : min;
        return min;
    }

    private static int maxIndex(int[] arr) {
        int maxIndex = 0;
        int maxValue = 0;
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] > maxValue) {
                maxValue = arr[i];
                maxIndex = i;
            }

        }
        return maxIndex;
    }

    private static int getMaxColor(int r, int g, int b) {
        int max = 0;
        max = r > max ? r : max;
        max = g > max ? g : max;
        max = b > max ? b : max;
        return max;
    }

    private static int getMaxColor2(int a, int b) {
        int max = 0;
        max = a > max ? a : max;
        max = b > max ? b : max;
        return max;
    }

    /**
     * 重置图片尺寸大小，等比缩放
     *
     * @param imageByte 图片byte数组
     * @param picWidth  图片宽度
     */
    public static byte[] resetImgSize(byte[] imageByte, Integer picWidth) throws Exception {
        ByteArrayInputStream is = new ByteArrayInputStream(imageByte);
        BufferedImage image = ImageIO.read(is);
        // 获取图片的宽度和高度
        double originalWidth = (double) image.getWidth();
        double originalHeight = (double) image.getHeight();

        if (picWidth == null || picWidth <= 0) {
            if ((int) originalWidth < SEAL_DEFAULT_WIDTH) {
                // 使用图片原始宽度作为宽度
                picWidth = (int) originalWidth;
            } else {
                // 使用印章默认宽度作为宽度
                picWidth = SEAL_DEFAULT_WIDTH;
            }
        }

        // 根据图片宽度计算图片高度，其实就是等比缩放
        int newHeight = (int) (picWidth / originalWidth * originalHeight);
        BufferedImage to = new BufferedImage(picWidth, newHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = to.createGraphics();
        to = g2d.getDeviceConfiguration().createCompatibleImage(picWidth, newHeight, Transparency.TRANSLUCENT);
        g2d.dispose();
        g2d = to.createGraphics();
        Image from = image.getScaledInstance(picWidth, newHeight, Image.SCALE_AREA_AVERAGING);
        g2d.drawImage(from, 0, 0, null);
        g2d.dispose();
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ImageIO.write(to, "png", byteArrayOutputStream);
        return byteArrayOutputStream.toByteArray();
    }

    /**
     * 设置图片透明度
     *
     * @param imageByte 图片byte数组
     * @param alphax    图片透明度
     */
    public static byte[] changeTransparency(byte[] imageByte, Double alphax) throws Exception {
        ByteArrayInputStream is = new ByteArrayInputStream(imageByte);
        BufferedImage image = ImageIO.read(is);

        // 高度和宽度
        int height = image.getHeight();
        int width = image.getWidth();

        // 生产背景透明和内容透明的图片
        ImageIcon imageIcon = new ImageIcon(image);
        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
        // 获取画笔
        Graphics2D g2D = (Graphics2D) bufferedImage.getGraphics();
        // 绘制Image的图片，使用了imageIcon.getImage()，目的就是得到image,直接使用image就可以的
        g2D.drawImage(imageIcon.getImage(), 0, 0, null);

        // 图片透明度
        int alpha = 0;
        // 外层遍历是Y轴的像素
        for (int y = bufferedImage.getMinY(); y < bufferedImage.getHeight(); y++) {
            // 内层遍历是X轴的像素
            for (int x = bufferedImage.getMinX(); x < bufferedImage.getWidth(); x++) {
                int rgb = bufferedImage.getRGB(x, y);
                // 对当前颜色判断是否在指定区间内
                if (colorInRange(rgb)) {
                    alpha = 0;
                } else {
                    // 设置为不透明
                    alpha = (int) Math.round(255 * alphax / 10);
                }
                // #AARRGGBB 最前两位为透明度
                rgb = (alpha << 24) | (rgb & 0x00ffffff);
                bufferedImage.setRGB(x, y, rgb);
            }
        }
        // 绘制设置了RGB的新图片,这一步感觉不用也可以只是透明地方的深浅有变化而已，就像蒙了两层的感觉
        g2D.drawImage(bufferedImage, 0, 0, null);

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ImageIO.write(bufferedImage, "png", byteArrayOutputStream);
        return byteArrayOutputStream.toByteArray();
    }

    /**
     * 判断是背景还是内容
     *
     * @param color
     * @return
     */
    public static boolean colorInRange(int color) {
        // 色差范围0~255
        int color_range = 210;
        // 获取color(RGB)中R位
        int red = (color & 0xff0000) >> 16;
        // 获取color(RGB)中G位
        int green = (color & 0x00ff00) >> 8;
        // 获取color(RGB)中B位
        int blue = (color & 0x0000ff);
        // 通过RGB三分量来判断当前颜色是否在指定的颜色区间内
        if (red >= color_range && green >= color_range && blue >= color_range) {
            return true;
        }
        return false;
    }

    public static FontMetrics createFontMetrics(Font font) {
        BufferedImage bufferedIamge = new BufferedImage(1, 1, 2);
        Graphics2D graphics2d = getSmoothGraphics2D(bufferedIamge);
        graphics2d.setFont(font);
        return graphics2d.getFontMetrics();
    }


    public static BufferedImage resizeCanvas(BufferedImage bufferedImage, int width, int height, int positionStyle) {
        int oldWidth = bufferedImage.getWidth();
        int oldHeight = bufferedImage.getHeight();
        BufferedImage resizedBufferedIamge = createTransparentBufferedImage(width, height);
        Graphics2D graphics2d = getSmoothGraphics2D(resizedBufferedIamge);
        int topLeftCornerX = 0;
        int topLeftCornerY = 0;
        switch (positionStyle) {
            case 1:
            case 4:
            case 7:
                topLeftCornerX = 0;
                break;
            case 2:
            case 5:
            case 8:
                topLeftCornerX = (width - oldWidth) / 2;
                break;
            case 3:
            case 6:
            case 9:
                topLeftCornerX = width - oldWidth;
        }

        switch (positionStyle) {
            case 1:
            case 2:
            case 3:
                topLeftCornerY = height - oldHeight;
                break;
            case 4:
            case 5:
            case 6:
                topLeftCornerY = (height - oldHeight) / 2;
                break;
            case 7:
            case 8:
            case 9:
                topLeftCornerY = 0;
        }

        graphics2d.drawImage(bufferedImage, topLeftCornerX, topLeftCornerY, (ImageObserver) null);
        graphics2d.dispose();
        return resizedBufferedIamge;
    }

    public static Graphics2D getSmoothGraphics2D(BufferedImage bufferedImage) {
        Graphics2D graphics2d = (Graphics2D) bufferedImage.getGraphics();
        setRenderingHint(graphics2d);
        return graphics2d;
    }

    public static void drawBorderedRoundRect(Graphics2D graphics2d, int width, int height, int border, int arcWidth, int arcHeight, int offset) {
        graphics2d.setStroke(new BasicStroke((float) border));
        graphics2d.drawRoundRect(0 + border / 2 + offset, 0 + border / 2 + offset, width - border - offset * 2, height - border - offset * 2, arcWidth, arcHeight);
    }

    public static void drawBorderedCircle(Graphics2D graphics2d, int width, int height, int border, int offset) {
        graphics2d.setStroke(new BasicStroke((float) border));
        graphics2d.drawOval(0 + border / 2 + offset, 0 + border / 2 + offset, width - border - offset * 2, height - border - offset * 2);
    }

    public static void setRenderingHint(Graphics2D graphics2d) {

        graphics2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
        graphics2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        graphics2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
        graphics2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
        graphics2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
        graphics2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        graphics2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        graphics2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
        graphics2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);

    }

    public static Font scaleFont(Font font, double xscale, double yscale) {
        AffineTransform scaleTransform = new AffineTransform();
        scaleTransform.scale(xscale, yscale);
        return font.deriveFont(scaleTransform);
    }

    public static void drawPentagram(Graphics g, int x0, int y0, int r) {
        int rr = (int) ((double) r * (Math.sin(Math.toRadians(54.0D)) - Math.cos(Math.toRadians(54.0D)) * Math.tan(Math.toRadians(36.0D))));
        int x1 = (int) ((double) x0 - (double) r * Math.cos(Math.toRadians(18.0D)));
        int y1 = (int) ((double) y0 - (double) r * Math.sin(Math.toRadians(18.0D)));
        int y2 = y0 - r;
        int x3 = (int) ((double) x0 + (double) r * Math.cos(Math.toRadians(18.0D)));
        int x4 = (int) ((double) x0 + (double) r * Math.cos(Math.toRadians(54.0D)));
        int y4 = (int) ((double) y0 + (double) r * Math.sin(Math.toRadians(54.0D)));
        int x5 = (int) ((double) x0 - (double) r * Math.cos(Math.toRadians(54.0D)));
        int xx1 = (int) ((double) x0 + (double) rr * Math.cos(Math.toRadians(18.0D)));
        int yy1 = (int) ((double) y0 + (double) rr * Math.sin(Math.toRadians(18.0D)));
        int yy2 = y0 + rr;
        int xx3 = (int) ((double) x0 - (double) rr * Math.cos(Math.toRadians(18.0D)));
        int xx4 = (int) ((double) x0 - (double) rr * Math.cos(Math.toRadians(54.0D)));
        int yy4 = (int) ((double) y0 - (double) rr * Math.sin(Math.toRadians(54.0D)));
        int xx5 = (int) ((double) x0 + (double) rr * Math.cos(Math.toRadians(54.0D)));
        Polygon polygon = new Polygon();
        polygon.addPoint(x1, y1);
        polygon.addPoint(xx4, yy4);
        polygon.addPoint(x0, y2);
        polygon.addPoint(xx5, yy4);
        polygon.addPoint(x3, y1);
        polygon.addPoint(xx1, yy1);
        polygon.addPoint(x4, y4);
        polygon.addPoint(x0, yy2);
        polygon.addPoint(x5, y4);
        polygon.addPoint(xx3, yy1);
        g.fillPolygon(polygon);
    }

    public static void drawClockwiseFanText(Graphics2D graphics2d, int width, int height, String text, Font fontText, int fanRadiusOfTextBaseline, double angleOfFan) {
        int centerX = width / 2;
        int centerY = height / 2;
        graphics2d.setFont(fontText);
        FontMetrics fontMetrics = graphics2d.getFontMetrics();
        char[] charsFanText = text.toCharArray();
        int wordWidth = fontMetrics.stringWidth(String.valueOf(charsFanText[0]));
        double OE = Math.sqrt((double) (fanRadiusOfTextBaseline * fanRadiusOfTextBaseline - wordWidth * wordWidth / 4));
        double angleBOE = Math.toDegrees(Math.atan2((double) (wordWidth / 2), OE));
        double angleBOC = 2.0D * angleBOE;
        double realAngleFan = angleOfFan + angleBOC;
        double deltaAngleWord = angleOfFan / (double) (text.length() - 1);

        for (int i = 0; i < charsFanText.length; ++i) {
            double angleCoordinateOfWord = 180.0D + deltaAngleWord * (double) i;
            angleCoordinateOfWord += 90.0D - realAngleFan / 2.0D;
            double angleWordToRotate = 270.0D + deltaAngleWord * (double) i;
            angleWordToRotate += angleBOE;
            angleWordToRotate += 90.0D - realAngleFan / 2.0D;
            double wordRelativeX = (double) fanRadiusOfTextBaseline * Math.cos(Math.toRadians(angleCoordinateOfWord));
            double wordRelativeY = (double) fanRadiusOfTextBaseline * Math.sin(Math.toRadians(angleCoordinateOfWord));
            AffineTransform wordTransform = AffineTransform.getRotateInstance(Math.toRadians(angleWordToRotate));
            wordTransform.scale(fontText.getTransform().getScaleX(), fontText.getTransform().getScaleY());
            graphics2d.setFont(fontText.deriveFont(wordTransform));
            graphics2d.drawString(String.valueOf(charsFanText[i]), (int) (wordRelativeX + (double) centerX), (int) ((double) centerY + wordRelativeY));
        }

    }


    public static void drawAnticlockwiseFanText(Graphics2D graphics2d, int width, int height, String text, Font fontText, int fanRadiusOfTextBaseline, double angleOfFan) {
        int centerX = width / 2;
        int centerY = height / 2;
        graphics2d.setFont(fontText);
        FontMetrics fontMetrics = graphics2d.getFontMetrics();
        char[] charsText = text.toCharArray();
        int wordWidth = fontMetrics.stringWidth(String.valueOf(charsText[0]));
        double OE = Math.sqrt((double) (fanRadiusOfTextBaseline * fanRadiusOfTextBaseline - wordWidth * wordWidth / 4));
        double angleBOE = Math.toDegrees(Math.atan2((double) (wordWidth / 2), OE));
        double angleBOC = angleBOE * 2.0D;
        double realAngleFan = angleOfFan + angleBOC;
        double deltaAngleWord = angleOfFan / (double) (text.length() - 1);

        for (int i = 0; i < charsText.length; ++i) {
            double angleCoordinateOfWord = 0.0D + deltaAngleWord * (double) i;
            angleCoordinateOfWord += 180.0D + (90.0D - realAngleFan / 2.0D);
            double angleWordToRotate = 270.0D - deltaAngleWord * (double) i;
            angleWordToRotate -= angleBOE;
            angleWordToRotate -= 180.0D + (90.0D - realAngleFan / 2.0D);
            double wordRelativeX = (double) fanRadiusOfTextBaseline * Math.cos(Math.toRadians(angleCoordinateOfWord));
            double wordRelativeY = (double) fanRadiusOfTextBaseline * Math.sin(Math.toRadians(angleCoordinateOfWord));
            AffineTransform wordTransform = AffineTransform.getRotateInstance(Math.toRadians(angleWordToRotate));
            wordTransform.scale(fontText.getTransform().getScaleX(), fontText.getTransform().getScaleY());
            graphics2d.setFont(fontText.deriveFont(wordTransform));
            graphics2d.drawString(String.valueOf(charsText[i]), (int) (wordRelativeX + (double) centerX), (int) ((double) centerY - wordRelativeY));
        }

    }

    public static void drawHorizontalCenteredText(Graphics2D graphics2d, int width, int height, String text, Font textFont, int textY) {
        graphics2d.setFont(textFont);
        FontMetrics fontMetrics = graphics2d.getFontMetrics();
        int textWidth = fontMetrics.stringWidth(text);
        graphics2d.drawString(text, width / 2 - textWidth / 2, textY);
    }


    public static void drawHorizontalCenteredText2(Graphics2D graphics2d, int width, int height, String text, Font textFont, int textY, int wordSpacing) {
        if (wordSpacing == 0) {
            drawHorizontalCenteredText(graphics2d, width, height, text, textFont, textY);
        } else {
            graphics2d.setFont(textFont);
            FontMetrics fontMetrics = graphics2d.getFontMetrics();
            char[] charsText = text.toCharArray();
            int textWidth = fontMetrics.stringWidth(text) + wordSpacing * (charsText.length - 1);
            int wordsWidth = 0;

            for (int i = 0; i < charsText.length; ++i) {
                int wordWidth = fontMetrics.charWidth(charsText[i]);
                graphics2d.drawString(String.valueOf(charsText[i]), width / 2 - textWidth / 2 + wordsWidth + i * wordSpacing, textY);
                wordsWidth += wordWidth;
            }

        }
    }
}
